from PyQt5.QtCore import QThread, pyqtSignal, pyqtSignal, QObject
import serial
import serial.tools.list_ports

EXPECTED_PACKAGE_SIZE = 11

class Communicate(QObject):
    signal_port = pyqtSignal(str)
    signal_portList = pyqtSignal(list)

class SerialThread(QThread):
    data_received = pyqtSignal(bytes)  # 用于发送数据的信号

    def __init__(self):
        super().__init__()
        self.ser = serial.Serial()
        self.buffer = bytearray()
        self.packet = bytearray()
        
    def open_port(self, port, baudrate, timeout = 1):
        try:
            self.ser.port = port
            self.ser.baudrate = baudrate
            self.ser.timeout = timeout
            self.ser.open()
            # self.ser.set_buffer_size(rx_size=4096, tx_size=4096)
            if self.ser.is_open:
                return 1
        except Exception as e:
            print(f"Failed to open serial port {port}: {e}")
            return 0

    def run(self):
        while self.ser.is_open:
            try:
                if self.ser.in_waiting:
                    data = self.ser.read(self.ser.in_waiting)
                    try:
                        #包是空的情况从0组包：
                        if not self.packet:
                            print(data)
                            # 确认头
                            if data[0] == 0xAA:
                                print(2)
                                if data[1] == 0xFA or data[1] == 0xF8:
                                    print(1)
                                    if len(data) >= 11: #收到正常或者粘黏frame
                                        for i in range(11):
                                            # self.packet.clear()
                                            self.packet.append(data[i])
                                        self.data_received.emit(bytes(self.packet)) # 组完清空
                                        print(self.packet)
                                        self.packet.clear()
                                    else: #分包的情况
                                        self.div_frame_len = len(data)
                                        print(f'self.div_frame_len{self.div_frame_len}')
                                        for i in range(len(data)):
                                            self.packet.append(data[i])
                        else: #包不是空的，但不够11帧，分包的情况
                            for i in range(11-self.div_frame_len):
                                self.packet.append(data[i])
                            if len(self.packet) == 11:
                                self.data_received.emit(bytes(self.packet)) # 组完清空
                                self.packet.clear() 
                    except:
                        self.packet.clear() 



                            # for byte in data:
                            #     # 如果检测到帧头，开始记录数据
                            #     if byte == 0xAA:
                            #             self.packet.clear()
                            #             self.packet.append(byte)
                            #     elif self.buffer:
                            #         # 如果检测到帧尾，结束记录并返回完整的数据包
                            #         self.buffer.append(byte)
                            #         if byte == end_byte:
                            #             print(f"完整包: {self.buffer}")
                            #             # 在这里处理你的数据包
                            #             self.buffer.clear()


            except serial.SerialException as e:
                print(f"Error reading from serial port: {e}")

    def process_data(self):
        while len(self.buffer) > 0:
            # 检查是否有足够的数据构成一个完整的包
            if len(self.buffer) >= EXPECTED_PACKAGE_SIZE:
                package = self.buffer[:EXPECTED_PACKAGE_SIZE]
                self.buffer = self.buffer[EXPECTED_PACKAGE_SIZE:]
                # self.handle_package(package)
                self.data_received.emit(bytes(package))
            else:
                break

    def write_data(self, data):
        if self.ser.is_open:
            self.ser.write(data)

    def stop(self):
        if self.ser.is_open:
            self.ser.close()
        self.quit()

    def com_search(self):
        cNums=[]
        clist = serial.tools.list_ports.comports()   #为所有的串口分别生成ListPortInfo object，列表封装
        i = 0
        for i in range(len(clist)):
            p = str(clist[i]).split(' - ')
            cNums.append(p[0])
        return cNums

    def build_frame(self, command, data_list):
        """
        构建数据帧并计算校验和。
        
        参数:
        command -- 命令关键字，1字节
        data_list -- 数据部分，字节列表
        
        返回:
        data_frame -- 完整的数据帧，字节串
        """
        # 同步字符
        sync_byte = 0xAA
        
        # 命令关键字，确保为单字节
        if not (0 <= command <= 255):
            raise ValueError("Command must be a single byte (0-255).")
        command_byte = command
        
        # 数据字节数
        data_byte_count = len(data_list)
        
        # 计算校验和（所有数据之和，取补码）
        checksum = sync_byte + command_byte + data_byte_count + sum(data_list)
        checksum = (~checksum + 1) & 0xFF  # 按位取反加1得到补码，并确保结果为单字节
        
        # 构建完整的数据帧
        data_frame = bytes([sync_byte, command_byte, data_byte_count]) + bytes(data_list) + bytes([checksum])
        
        return data_frame
    
    def parse_frame(self, data_frame):
        """
        解析数据帧并验证校验和。
        
        参数:
        data_frame -- 完整的数据帧，字节串
        
        返回:
        command -- 命令关键字
        data_list -- 数据部分，字节列表
        is_valid -- 校验和是否有效
        """
        if len(data_frame) != 11:
            raise ValueError("Data frame length != 11.")
        
        sync_byte = data_frame[0]
        command = data_frame[1]
        data_byte_count = data_frame[2]
        data_list = list(data_frame[3:-1])
        checksum = data_frame[-1]
        print(str(command))
        # 计算校验和
        calculated_checksum = sync_byte + command + data_byte_count + sum(data_list)
        calculated_checksum = (~calculated_checksum + 1) & 0xFF
        
        is_valid = (checksum == calculated_checksum)
        
        return command, data_list, is_valid


if __name__ == '__main__':
    # 示例：构建一个数据帧
    serial_thread = SerialThread()
    command = 0xF8  # 命令关键字示例
    # data_list = [0x00, 0x00, 0x00, 0XF0, 0XF0, 0XF0, 0XF0]  # 数据部分示例 运动+上电
    data_list = [0x00, 0x01, 0x01, 0XF0, 0XF0, 0XF0, 0XF0]  # 数据部分示例 运动+上电
    data_frame = serial_thread.build_frame(command, data_list)
    print("Data Frame:", data_frame.hex())  # 输出数据帧的十六进制表示


